# -*- coding: utf-8 -*-
# Changes:
# Added NickServ identification function
# Added NickServ password change function
# Added ignore & unignore function

import socket
import string
import sys
import time
import random
import re
import cPickle
import urllib
import math
import datetime
from xml.etree import ElementTree as ET

class keebot():
    def __init__(self,*args,**kwargs):
        
        # Load settings from file
        SETTINGS = open('settings.cfg', 'r')
        self.settings = cPickle.load(SETTINGS)
        SETTINGS.close()
        print 'Loaded settings.'
        
                
        # Load ignore list
        IGNORE = open('ignore.db', 'r')
        self.ignoreList = cPickle.load(IGNORE)
        IGNORE.close()
        print 'Loaded ignore list.'
        
        
        
        # Load triggers from file 
        DB = open('data.db','r')
        self.triggers = cPickle.load(DB)
        
        print 'Loaded trigger database.' 
        
        DB.close()

        
        # Connect to server
        self.irc = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
        self.irc.connect((self.settings['network'],self.settings['port']))
        self.irc.recv(4096)
        self.irc.send('NICK ' + self.settings['botnick'] + '\r\n')
        self.irc.send('USER m00 m00 m00 :m00 harr\r\n')
        self.irc.send('JOIN ' + self.settings['channel'] + '\r\n')
        self.irc_connected = True


    def sendMsg(self, destination, text, action = False):
        """
        Send a message to the destination.
        Set action to True for /me kind of message.
        """
        
        # make sure the text is a string
        if type(text) != str:
            
            try:
                text = str(text)
            
            # if it's unicode type it'll 
            # go mad when you try to str() it
            # so encode it into utf-8
            except:
                text = text.encode('utf-8')
        

        if action == False:
            self.irc.send('PRIVMSG ' + destination + ' :' + text +'\r\n')
        elif action == True:
            self.irc.send ('PRIVMSG ' + destination + ' :\001ACTION ' + text + '\001\r\n')

    def quit(self, destination, text, quiet = False):
        """
        Send a message to the channel then die.
        Set quiet = True to disable the message sending.
        """
        if quiet == False:
            self.irc.send('PRIVMSG ' + destination + ' :' + text + '\r\n')
        self.irc.send('QUIT \r\n')
    
    def whoisNewNick(self, nick):
        """
        Whois the nickname which the bot is supposed to change to.
        Return True if the nickname isn't taken.
        """
        self.irc.send('whois ' + nick + '\r\n')
        tmp = self.irc.recv(4096)
        tmp = tmp.split(':')[2].strip()
        
        if tmp == 'No such nick/channel':
            return True
        else:
            return False
    
    def changeNick(self, nick):
        """
        Change bot nickname
        """
        
        if self.whoisNewNick(nick) == True:
            self.settings['botnick'] = nick
            self.irc.send('NICK ' + self.settings['botnick'] + '\r\n')
        else:
            say_msg = nick + ' is already taken.'
            self.sendMsg(self.settings['channel'], say_msg)
        
    def getNames(self):
        """
        Get nicknames from the current channel
        """
        
        self.irc.send('NAMES ' + self.settings['channel'] + '\r\n')
        names = self.irc.recv(4096)
        names = names.split(':')
        names = names[2].strip()
        names = names.split()
        
        for item in names:
            
            # strip @ (op) and +(voice) from nicks 
            names[names.index(item)] = item.strip('@+')
        
        # remove the entry that has the bot's nickname
        del names[names.index(self.settings['botnick'])]

        return names
    
    def randomNick(self):
        """
        Get random nickname from channel, excluding the bot nickname.
        """
        name = self.getNames()
        
        # get random name from name list (excepting bot name)
        name = random.choice(name)
        
        return name
    
    def getNick(self):
        """
        Get the nickname of the one who said the most recent line.
        """
        name = self.data.split('!')
        
        name = name[0].strip(':')
        
        return name

    def checkNick(self, nick):
        """
        Return 2 if nick is bot owner, 1 if moderator, 0 if regular user
        """ 
    
        if nick == self.settings['botowner']:
            return 2
        elif nick in self.settings['botmods']:
            return 1
        else:
            return 0
    
    def changeChannel(self,chan):
        """
        Move bot to another channel (it parts the old one).
        """
        say_msg = 'Moving to ' + chan + '.'
        self.sendMsg(self.settings['channel'], say_msg)
        self.irc.send('PART ' + self.settings['channel'] + '\r\n')
        self.settings['channel'] = chan
        self.irc.send('JOIN ' + self.settings['channel'] + '\r\n')
        
    def checkIfSelfTarget(self):
        """
        Checks if the message line starts with the bot nickname
        """
        if self.words[0] == self.settings['botnick'] or self.words[0] == (self.settings['botnick'] + ":") or self.words[0] == (self.settings['botnick'] + ",") or self.words[0] == (self.settings['botnick'] + "!"):
            return True
        else:
            return False
    
    def checkModList(self, name):
        """
        Check the bot_mod list to see if the given name is inside it.
        Returns True if name is in the list, False if name isn`t in the list
        """
        if name in self.settings['botmods']:
            return True
        else:
            return False
    
    def checkTriggers(self):
        """
        Checks if what has been said triggers in word list.
        If it is, it returns the reply list.
        Else returns false.
        """
        
        # convert word list to string
        
        txt = ' '.join(self.words)
        
        # if string is null abort

        if len(txt) == 0:
            
            return False
            
        else:
        
            # get regexp syntax from the triggers dictionary's keys
            
            for regexp in self.triggers:

                # compare regexp from trigger with the txt var 
                
                rg = re.compile(regexp,re.IGNORECASE|re.DOTALL)
                match = rg.search(txt)
                
                if match:
                    response = self.triggers[regexp]

                    # choose random reply based on the length of the replies list
                    # -1 because the numbering starts from 1 not from 0 
                    # and the list index starts from 0

                    response = random.choice(response)
                    
                    count = response.count('$')
           
                    if count > 0:
                        for i in range(0,count):
                            
                            try:
                            # check for numerical vars ($0, etc)
                                tmp = ' '.join(self.words)
                                
                                tmp = tmp[match.end(i+1):]
 
                                tmp = tmp.split()
                                

                                times = re.subn('\$'+str(i),tmp[0],response)
                                
                                if times[1] > 0:
                                    response = re.sub('\$'+str(i), str(tmp[0]), response)


                            except:
                                pass
                            
                            try:
                            # check for random nick vars
                                
                                # search for $R and count the times it is found
                                times = re.subn('\$R', 'count', response)
                                
                            
                                for i in range(times[1]):
                                    rand_nick = self.randomNick()
                                    
                                    # replace $R with a random nickname
                                    response = re.sub('\$R',rand_nick,response)

                            except Exception, inst:
                                pass
                            
                            
                            try:
                            # check for talker's nick var
                                times = re.subn('\$N', 'count', response)
                                nick = self.getNick()
                                
                                for i in range(times[1]):
                                    response = re.sub('\$N', nick, response)

                            except:
                                pass
                            
                            try:
                            # check for nicks var. $E = everybody
                                times = re.subn('\$E', 'count', response)
                                nicks = ', '.join(self.getNames()) + ', ' + self.settings['botnick']
                                
                                for i in range(times[1]):
                                    response = re.sub('\$E', nicks, response)
                            
                            except Exception, inst:
                                pass
                            
                            try:
                            # check for time var $T
                                times = re.subn('\$T', 'count', response)

                                # get local time
                                time_is = time.strftime('%H:%M:%S')
                                
                                for i in range(times[1]):
                                    response = re.sub('\$T', time_is, response)

                            
                            except Exception, inst:
                                pass
                            
                            try:
                            # check for bot nickname var $B
                                times = re.subn('\$B', 'count', response)
                                botnick = self.settings['botnick']
                                for i in range(times[1]):
                                    response = re.sub('\$B', botnick, response)
                                
                            except:
                                pass
        
                        return response
                        
                    else:
                        return response
        
        return False 


    def addTrigger(self,trigger):
        """
        Adds replies to triggers.
        Trigger replies must be added as lists so they can be called like reply[x]
        """
        # create a string from the word list
        trigger = ' '.join(trigger)
        
        # split the string into two parts
        trigger = trigger.split('_FOR_')
        
        reply = trigger[1]
        trigger = trigger[0]
        
        # if the trigger isn`t already in the trigger dictionary
        # add it and create an empty list for the replies
        if not trigger in self.triggers:
            self.triggers[trigger] = []
        

        # append the reply to the trigger in the dictionary
        
        
        self.triggers[trigger].append(reply)
   
   
    def remTrigger(self,trigger):
        """
        Removes given trigger from trigger list.
        """
        
        trigger = ' '.join(trigger)
        
        if trigger in self.triggers:
            del self.triggers[trigger]
        else:
            return False
    
        
    def remTriggerReply(self,trigger,which):
        """
        Removes given reply from the trigger.
        """
        try:
            which = int(which)

            if self.triggers[trigger][which] != None and len(self.triggers[trigger]) > 1:
                
                tmp = self.triggers[trigger][which]
                                
                # remove the reply
                del self.triggers[trigger][which]
                
                say_msg = 'Removed ' + tmp + '.'
                self.sendMsg(self.settings['channel'], say_msg)
                
            else:
                say_msg = 'That is the only item in the list. Remove the trigger instead.'
                self.sendMsg(self.settings['channel'], say_msg)
             
        except Exception, inst:
            say_msg = 'Couldn`t remove reply \'' + whdich + '\' from ' + trigger + ' because: ' + str(inst.args) + '.'
            self.sendMsg(self.settings['channel'], say_msg)
        
    def searchTrigger(self,trigger):
        
        # convert to string
        trigger = str(trigger)
        
        # check search string is longer than 3 chars
        if len(trigger) < 3:
            
            # announce that search string is too short then gtfo
            say_msg = 'Search string must be at least 3 characters long'
            self.sendMsg(self.settings['channel'], say_msg)
            
            return False
        
        else:
            
            # get trigger keys from dictionary to search within them
            search_here = self.triggers.keys()
            
            # create a list for the results
            say_msg = []
            
            # iterate through the triggers and search for the word
            for item in search_here:
                
                if item.find(trigger) != -1:
                    
                    # if item is found get its index from the list, get the 
                    # list item with that index and append it to the reply list 
                    say_msg.append(search_here[search_here.index(item)]) 
            
            # if say_msg is empty -> no matches -> announce that
            
            if len(say_msg) == 0:
                say_msg = 'No matches. Please insert coin to continue.'
                self.sendMsg(self.settings['channel'], say_msg)
            else:
                self.sendMsg(self.settings['channel'], say_msg)
            
   
    def saveStuff(self):
        """
        Save everything in the corresponding files.
        """
        # try to open trigger database
        try:
            DB = open('data.db','w')
            cPickle.dump(self.triggers,DB)
            DB.close()
            say_msg = 'Saved trigger database. '
        
        # if it fails show the cause
        except Exception, inst:
            say_msg = 'Failed saving trigger database: ' + str(inst.args)
        
        # try to open settings file
        try:
            SETTINGS = open('settings.cfg','w')
            cPickle.dump(self.settings,SETTINGS)
            SETTINGS.close()
            say_msg += 'Saved settings. '
        
        # if it fails show the cause
        except Exception, inst:
            say_msg += 'Failed saving settings: ' + str(inst.args)
        
        # try to open ignore file
        try:
            IGNORE = open('ignore.db', 'w')
            cPickle.dump(self.ignoreList,IGNORE)
            IGNORE.close()
            say_msg += 'Saved ignore list. '
        
        except Exception, inst:
            say_msg += 'Failed saving ignore list: ' + str(inst.args)
        
        # relay success/fail message to channel
        self.sendMsg(self.settings['channel'], say_msg)
            
    def searchYahoo(self, keywords, results = 3, multilines = False):
        """
        Search for whatever using Yahoo search.
        Why Yahoo instead of Google?
        Because Yahoo can return search results
        as XML and doesn\`t block urllib like 
        Google does.
        Default results returned = 3.
        Set multilines to True to return each result
        on a different line
        """
        # convert results from int to str
        # so it can be concatenated with the url below
        results = str(results)
        
        # no keywords given
        if len(keywords.split())<=0:
            
            say_msg = "Turn back or I WILL kill you. I'm going to kill you, and all the cake is gone."
            self.sendMsg(self.settings['channel'], say_msg)
            
            return 'OHSHI-!! Divide by zero!' # really!
        
        # if it's just one keyword, use "keyword" to
        # exclude the insertion of 'suggested 
        # different/fucked up spelling' from Yahoo
        elif len(keywords.split())==1:
            keywords = '\"' + keywords + '\"'
        
        # if more than one keyword, split them up and
        # transform the whitespaces in %20
        else:
            keywords = keywords.split()
            keywords = '%20'.join(keywords)
    
        url = 'http://search.yahooapis.com/WebSearchService/V1/webSearch?appid=keebot&adult_ok=1&results=' + results + '&query=' + keywords

        # just reuse the results var
        results = urllib.urlopen(url)

        tree = ET.parse(results)
        
        # get the root of the tree
        # so we can get the childs
        # (because children are depreciated!...heh)
        root = tree.getroot()
        
        # and recycling the var again
        results = []
        
        # each child is a result
        # each result has 8 or so childz
        # child 0 = page title
        # child 1 = page description
        # child 2 = url
        # child 3 = ?????
        # child 4 = PROFIT
        # after child 2, stuff is unimportant
        # poke around and see what the others are if you care
        for item in root._children:
            
            # get just the first 50 letters of the title
            # it's not THAT important to have it all, right?
            # then add some separator, then add the url
            
            aux = item[0].text[:50] + " // " + item[2].text
           
            # append it all to the results 
            results.append(aux)
        
        # if no results found, blame someone!
        if len(results) == 0:
            results.append('No results. Blame Yahoo and Google!')
            
        if multilines == False:
            # separate the results with something
            results = ' *** '.join(results)
        
            # then post the results in the channel
            self.sendMsg(self.settings['channel'], results)
            
        
        elif multilines == True:
            for item in results:
                self.sendMsg(self.settings['channel'], item)           
    
    def randInt(self,numbers):
        """
        Return a random integer using numbers[0] and
        numbers[1] as interval limits
        """
        
        try:
            say_msg = random.randint(int(numbers[0]),int(numbers[1]))
            self.sendMsg(self.settings['channel'], say_msg)
        
        except Exception, inst:
            say_msg = str(inst.args)
            self.sendMsg(self.settings['channel'], say_msg)
        
    def isIgnored(self,nick):
        if nick in self.ignoreList:
            return True
        else:
            return False
        
    def ignore(self,nick):
        
        # converts to lowercase for easier management
        nicklow = nick.lower()
        
        # check if nickname isn`t already ignored
        if nicklow in self.ignoreList:
            say_msg = nick + ' already ignored.'
        
        # check if the nickname is a mod or owner
        elif nicklow in self.settings['botowner'] or nicklow in self.settings['botmods']:
            say_msg = 'Can`t ignore a mod or owner. Remove some privileges and try again. ^_^'
        
        # ignore the nickname
        else:
            self.ignoreList.append(nicklow)
            say_msg = nick + ' is now ignored. \o/'
        
        
        self.sendMsg(self.settings['channel'], say_msg)
            
    
    def unignore(self,nick):
        
        nicklow = nick.lower()
        
        # check if nickname is on the ignore list
        if nicklow in self.ignoreList:
            self.ignoreList.remove(nicklow)
            say_msg = nick + ' unignored.'
        
        else:
            say_msg = nick + ' isn`t ignored.'
        
        self.sendMsg(self.settings['channel'], say_msg)
        
        
    def mainLoop(self):
        while self.irc_connected:
            # var to disable replying when adding/removing triggers
            # because I am too lazy to use elif
            # must be added after each trigger related function 
            trg = False
            self.data = self.irc.recv(4096)
            
            # show messages recieved from server
            print self.data
            
            # pong the server back
            if self.data.find('PING') != -1:
                PONG = 'PONG ' + self.data.split() [1] + '\r\n'
                self.irc.send (PONG)
            
            # see if the message from the server contains PRIVMSG
            elif self.data.find('PRIVMSG') != -1:
                # get nickname of the one who said whatever's been said
                nick = self.getNick()
                
                
                # 1. split the data string into a list using ':' as delimiter
                # 2. get the elements starting from the second (in case the message contains ':')
                # 3. join those elements into a string separating them with a whitespace ( but deletes the ':' from the sentece )
                # 4. ??????
                # 5. PROFIT
                self.message = ':'.join(self.data.split(':')[2:])
                

                # self.words = list any message that is received via PRIVMSG
                self.words = self.message.split(' ')
                
                # strip it
                self.words[len(self.words)-1]=self.words[len(self.words)-1].strip()
                
                
                
                try:
                    self.cmd = self.words[1]
                    if self.cmd == '':
                        raise Exception
                except:
                    self.cmd = 'calling you'
                
                # owner and mod commands
                # self.checkNick - 0 = regular user, 1 = mod, 2 = owner
                # self.checkIfSelfTarget - True: sentence starts with botnick, False: it doesn`t
                
                # commands for owner and mods
                if not self.isIgnored(nick.lower()):
                    if self.checkNick(nick) >= 1:
                        # kill bot - owner only
                        if self.checkNick(nick) >= 2 and self.checkIfSelfTarget() and self.cmd == 'die':
                            
                            self.saveStuff()
                            self.irc_connected = False
                        
                        # change owner - owner only
                        if self.checkNick(nick) >= 2 and self.checkIfSelfTarget() and self.cmd == 'chown':
                            
                            self.settings['botowner'] = self.words[2]
                            say_message = 'Owner changed to ' + self.settings['botowner'] + '.\r\n'
                            self.sendMsg(self.settings['channel'], say_message)
                        
                        # search for a trigger - mods & owner 
                        if self.checkNick(nick) >= 1 and self.checkIfSelfTarget() and self.cmd == 'searchtrigger':
                            search_for = self.words[2]
                            self.searchTrigger(search_for)
                            
                        # displays the replies for a given trigger - mods & owner 
                        if self.checkNick(nick) >= 1 and self.checkIfSelfTarget() and self.cmd == 'display':
                            trigger = ' '.join(self.words[2:])
    
                            if trigger in self.triggers:
                                say_msg = self.triggers[trigger]
                            else:
                                say_msg = 'Trigger not found. But relax, in the end there will be cake!'
                                
                            self.sendMsg(self.settings['channel'], say_msg)
                            trg = True
                                
                        # add moderator - owner only
                        if self.checkNick(nick) >= 2 and self.checkIfSelfTarget() and self.cmd == 'addmod':                
                          
                            if self.checkModList(self.words[2]):
                                # name already on the list - abort
                                say_message = 'User ' + self.words[2] + ' already in moderator list.\r\n'
                                self.sendMsg(self.settings['channel'], say_message)
                                
                            elif not self.checkModList(self.words[2]):
                                # add name to list
                                self.settings['botmods'].append(self.words[2])
                                say_message = 'Added user ' + self.words[2] + ' to moderator list.\r\n'
                                self.sendMsg(self.settings['channel'], say_message)
                        
                        # remove moderator - owner only
                        if self.checkNick(nick) >= 2 and self.checkIfSelfTarget() and self.cmd == 'delmod':              
                          
                            if self.checkModList(self.words[2]):
                                # name is on the list - remove
                                self.settings['botmods'].remove(self.words[2])
                                say_message = 'Moderator ' + self.words[2] + ' removed.\r\n'
                                self.sendMsg(self.settings['channel'], say_message)
                            
                            elif not self.checkModList(self.words[2]):
                                # name is not on the list - abort
                                say_message = 'Moderator ' + self.words[2] + ' was not found.Aborting.\r\n'
                                self.sendMsg(self.settings['channel'], say_message)
                        
                        # change channel
                        if self.checkNick(nick) >= 2 and self.checkIfSelfTarget() and self.cmd == 'changechan':
                            self.changeChannel(str(self.words[2]))
                        
                        # change bot nick
                        if self.checkNick(nick) >= 2 and self.checkIfSelfTarget() and self.cmd == 'chnick':
                            self.changeNick(self.words[2])
                        
                        # change NickServ pass
                        if self.checkNick(nick) >= 2 and self.checkIfSelfTarget() and self.cmd == 'chnspass':
                            try:
                                self.settings['nspass'] = self.words[2]
                                print 'NS Password changed to ' + self.settings['nspass']
                            except Exception, inst:
                                say_msg = 'DANGER, WILL ROBINSON!' + 'AND'.join(inst.args)
                                self.sendMsg(self.settings['channel'], say_msg)
                            
                        # identify with NickServ
                        if self.checkNick(nick) >= 2 and self.checkIfSelfTarget() and self.cmd == 'nsidentify':
                            try:
                                say_msg = 'identify ' + self.settings['nspass']
                                self.sendMsg('NickServ', say_msg)
                            except Exception, inst:
                                say_msg = 'DANGER, WILL ROBINSON!' + 'AND'.join(inst.args)
                                self.sendMsg(self.settings['channel'], say_msg)
                        
                        
                            
                        # say stuff
                        if self.checkIfSelfTarget() and self.cmd == 'say':
                            say_message = ' '.join(self.words[2:])
                            self.sendMsg(self.settings['channel'],say_message)
                        
                        # get http header - Made by Skee
                        if self.checkIfSelfTarget() and self.cmd == 'head':
                            host = self.words[2]
                        
                            if host.find('http://') != -1:
                                print host
                                host = host[7:]
                            server = host.split('/')[0]
                            uri = host[len(server):]
                         
                            if uri == '':
                                uri = '/'
                           
                            try:
                                q = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                                q.connect((server, 80))
                                q.send ('HEAD ' + uri + ' HTTP/1.0\r\n')
                                q.send ('Host:  '+ server + '\r\n')
                                q.send ('\r\n')
                                rec = q.recv(4096)
                                rec = string.replace(rec,'\n',' ')
                                rec = string.replace(rec,'\r',' ')
                          
                            except:
                                rec = 'ups, eroare: ' + str( sys.exc_info() ) + 'host: ' + host
            
                            self.sendMsg(self.settings['channel'], rec)
                            # message HTTP HEAD result for host (param 1)
                        
                        # get host - Made by Skee
                        if self.checkIfSelfTarget() and self.cmd == 'host':
                            host = self.words[2]
                            
                            try:
                                ip = socket.gethostbyname(host)
                            
                            except:
                                ip = 'could not resolve ' + host
                            self.sendMsg(self.settings['channel'], ip)
                            # message host's ip
                        
                        
                        # save triggers, ignore list and settings
                        if self.checkIfSelfTarget() and self.cmd == 'saveall':
                            self.saveStuff()
                        
                        # ignore someone
                        if self.checkIfSelfTarget() and self.cmd == 'ignore':
                            self.ignore(self.words[2])
                            
                        # unignore someone
                        if self.checkIfSelfTarget() and self.cmd == 'unignore':
                            self.unignore(self.words[2])
                        
                    # regular user commands
                    
                    # give link for google query  
                    if self.checkIfSelfTarget() and self.cmd == 'google':
                        say_message = 'http://www.google.com/search?q=' + '+'.join(self.words[2:])
                        self.sendMsg(self.settings['channel'],say_message)
                    
                    # search Yahoo and return the first 3 links
                    if self.checkIfSelfTarget() and self.cmd == 'search':
                        keywords = str(' '.join(self.words[2:]))
                        self.searchYahoo(keywords,multilines=True)
                        
                    # do a "feeling lucky" search using Yahoo...keke
                    if self.checkIfSelfTarget() and self.cmd == 'lucky':
                        keywords = str(' '.join(self.words[2:]))
                        self.searchYahoo(keywords, results = 1)
                        
                    # return a Wikipedia search link
                    if self.checkIfSelfTarget() and self.cmd == 'wp':
                        keywords = str('+'.join(self.words[2:]))
                        say_msg = "http://en.wikipedia.org/wiki/Special:Search?search=" + keywords
                        self.sendMsg(self.settings['channel'], say_msg)
                    
                    # return a Dictionary.com search link
                    if self.checkIfSelfTarget() and self.cmd == 'dict':
                        keywords = str('+'.join(self.words[2:]))
                        say_msg = 'http://dictionary.reference.com/browse/' + keywords
                        self.sendMsg(self.settings['channel'], say_msg)
                    
                    # return a random integer from within an interval
                    if self.checkIfSelfTarget() and self.cmd == 'randint':
                        try:
                            numbers = []
                            numbers.append(self.words[2])
                            numbers.append(self.words[3])
                            self.randInt(numbers)
                            
                        except Exception, inst:
                            say_msg = str(inst.args)
                            self.sendMsg(self.settings['channel'], say_msg)
                    
                    # display length of given string
                    if self.checkIfSelfTarget() and self.cmd == 'len':
                        say_msg = len(' '.join(self.words[2:]))
                        
                        self.sendMsg(self.settings['channel'], say_msg)
    
                    # display moderators
                    if self.checkIfSelfTarget() and self.cmd == 'showmods':
                        self.sendMsg(self.settings['channel'], self.settings['botmods'])
                        
                    # say something when someone says the bot nickname
                    if self.checkIfSelfTarget() and self.cmd == 'calling you':
                        say_message = 'Hey look at that thing. Noo, that other thing.'
                        self.sendMsg(self.settings['channel'],say_message)
         
                    # if no direct command was issued (google search, add mod, etc)
                    # look for triggers in the channel text and react accordingly
                    # add trigger
                   
                   # add trigger - mod & owner
                    if self.checkNick(nick) >= 1 and self.checkIfSelfTarget() and self.cmd == 'add':
                        self.addTrigger(self.words[2:])
                        say_msg = 'Done.'
                        self.sendMsg(self.settings['channel'], say_msg)
                        trg = True
                        
                    # remove trigger - mod & owner
                    if self.checkNick(nick) >= 1 and self.checkIfSelfTarget() and self.cmd == 'remove':
                       if self.remTrigger(self.words[2:]) == False:
                           say_msg = '\'' + str(self.words[2:]) + '\' trigger not found.'
                           self.sendMsg(self.settings['channel'], say_msg)
    
                        
                       else:
                           say_msg = 'Removed ' + ' '.join(self.words[2:])
                           self.sendMsg(self.settings['channel'], say_msg)
                           
                       trg = True
                    
                   # remove a certain reply from a trigger - mod & owner
                    if self.checkNick(nick) >= 1 and self.checkIfSelfTarget() and self.cmd == 'remreply':
                        # take the elements from 2 til the end except the last one
                        # and create a string 
                        
                        trigger = ' '.join(self.words[2:-1])
                        
                        # which = last element
                        which = self.words[-1]
                        
                        self.remTriggerReply(trigger, which)
                        trg = True
                        
                    elif trg == False:
                        
                        reply = self.checkTriggers()
                       
                        if reply != False:
                            # check if the reply starts with +
                            # the char that tells keebot it needs 
                            # to perform an action (idea stolen from darkbot)
                            
                            if reply.split()[0] == '+':
                                # split the string so you can remove the "+" from the beginning
                                reply = reply.split()
                                reply = reply[1:]
    
                                # now form a string with the removed "+" and perform it as an action  
                                
                                reply = ' '.join(reply)
                                self.sendMsg(self.settings['channel'], reply, 1)
                                 
                            else:
                                self.sendMsg(self.settings['channel'], reply)
                else:
                    print nick + ' is ignored. Moving along.'

        
        # after exiting while loop, quit irc and close socket
        self.quit(self.settings['channel'],self.settings['quit_msg'])
        self.irc.close()
        
if __name__ == '__main__':
    try:
        bot = keebot()
        bot.mainLoop()
        
    except Exception, inst:
        log = open('error log.txt','a')
        local_date = datetime.date.today()
        local_date = local_date.isoformat()
        local_time = time.strftime('%H:%M:%S')
        print 'ERROR: ' + str(inst.args)
        err_msg = local_date + ' ' + local_time + ": \n" + ' '.join(inst.args) + '\n\nWords were:\n' + str(bot.words) + '\n\n\n'
        log.write(err_msg)
        log.close()
